﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using ProCP.Sim;

namespace ProCP
{
    public partial class Form1 : Form
    {
        //*** Simulation
        BinarySerializationHelper binaryHelper;
        string currentfile;
        Simulation SFromFile;
        Simulation s;
        int[] CheckEdges;
        List<TrafficOutSettings> TrafficOutValues;
        bool run = false; // not sure stop background wroker should be enought but may hapen in modle of simulation... 

        Form2 form2;
        int selectedPosition;


        public Form1()
        {
            InitializeComponent();
            form2 = new Form2();
            backgroundWorkerSimulation.WorkerReportsProgress = true;
            backgroundWorkerSimulation.WorkerSupportsCancellation = true;
            binaryHelper = new BinarySerializationHelper();
            CheckEdges = new int[4];
            TrafficOutValues = new List<TrafficOutSettings>();

        }
        //Comment on toolstripButton
        private void toolStripButtonStart_Click(object sender, EventArgs e)
        {
            run = true;
            backgroundWorkerSimulation.RunWorkerAsync();
            playBtn.Enabled = false;
            pauseBtn.Enabled = true;
        }

        private void toolStripButton7_Click(object sender, EventArgs e)
        {
            playBtn.Enabled = true;
        }

        private void toolStripButton5_Click(object sender, EventArgs e)
        {
            if (backgroundWorkerSimulation.WorkerSupportsCancellation == true)
            {
                // Cancel the asynchronous operation.
                backgroundWorkerSimulation.CancelAsync();
                playBtn.Enabled = true;
                pauseBtn.Enabled = false;
            }
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            s.Draw(e.Graphics);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            var mouseCoordinates2 = this.PointToClient(Cursor.Position);
            toolStripLabel1.Text = Convert.ToString(mouseCoordinates2.X) + " " + Convert.ToString(mouseCoordinates2.Y - 25);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            s = new Simulation(
                new Size(4, 3),
                new Point(20, 20),
                new Size(200, 200));
            this.DoubleBuffered = true;
            s.AddCrossing(0, 1);
            s.AddCrossing(1, 1);
            s.AddCrossing(2, 1);
            s.AddCrossing(3, 1);

            s.AddCrossing(4, 1);
            s.AddCrossing(5, 1);
            s.AddCrossing(6, 1);
            s.AddCrossing(7, 1);

            s.AddCrossing(8, 1);
            s.AddCrossing(9, 1);
            s.AddCrossing(10, 1);
            s.AddCrossing(11, 1);

        }

        private void backgroundWorkerSimulation_DoWork(object sender, DoWorkEventArgs e)
        {
            var counter = 0;
            var worker = sender as BackgroundWorker;
            while (true)
            {
                if (worker.CancellationPending == true)
                {
                    e.Cancel = true;
                    break;
                }
                Thread.Sleep(10);
                s.RunSimaulation();
                counter++;
               
                worker.ReportProgress(counter);
                this.Invoke((MethodInvoker)delegate { label9.Text = s.cMap[0].carsInCrossing.Count.ToString(); }); 

            }
        }

        private void backgroundWorkerSimulation_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            toolStripLabel2.Text = ("Runing: " + e.ProgressPercentage.ToString() + " sec");
            RefreshForm();
        }

        private void backgroundWorkerSimulation_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled == true)
            {
                toolStripLabel2.Text = "Paused!";
            }
            else if (e.Error != null)
            {
                toolStripLabel2.Text = "Error: " + e.Error.Message;
                MessageBox.Show(e.Error.ToString());
            }
            else
            {
                toolStripLabel2.Text = "Done!";
            }
        }

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            using (Graphics g = this.grid.CreateGraphics())
            {
                grid.Text = null;
                this.Refresh();
                selectedPosition = s.MouseClickToPossition(e.Location);

                if (!run && e.Button == MouseButtons.Right)
                {

                    if (s.IsEmpty(selectedPosition))
                    {
                        PopupMenuStrip.Items[1].Enabled = false;
                        PopupMenuStrip.Items[2].Enabled = false;
                    }
                    else
                    {
                        PopupMenuStrip.Items[1].Enabled = true;
                        PopupMenuStrip.Items[2].Enabled = true;
                    }

                    if (selectedPosition >= 0)
                    {
                        s.DrawSelectedRectangle(g, selectedPosition);
                        PopupMenuStrip.Show(Cursor.Position);
                    }

                }
                else if (playBtn.Enabled && e.Button == MouseButtons.Left)
                {
                    if (selectedPosition >= 0)
                    {
                        s.DrawSelectedRectangle(g, selectedPosition);
                    }
                }
            }
        }

        //Refresh method for backgroudnworker
        private void RefreshForm()
        {
            this.grid.Refresh();
        }

        private void add_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            switch (e.ClickedItem.ToString())
            {
                case "Add/Change Crossing":
                    using (var fr2 = new Form2())
                    {
                        int type = -1;
                        var result = fr2.ShowDialog();
                        if (result == DialogResult.OK)
                        {
                            type = fr2.ReturnValue1;            //values preserved after close
                            s.AddCrossing(selectedPosition, type + 1);
                        }
                        this.Refresh();
                    }
                    break;
                case "Remove":
                    if (selectedPosition >= 0)
                    {
                        s.RemoveCrossing(selectedPosition);
                        this.Refresh();
                    }
                    break;
                case "Settings":
                    using (var fr3 = new Settings(s.GetCrossType(selectedPosition), s.Checkneighbors(selectedPosition), selectedPosition, this))
                    {
                        var result = fr3.ShowDialog();
                        if (result == DialogResult.OK)
                        {
                            MessageBox.Show("Traffic lights time changed");
                            s.SetTrafficLight(selectedPosition, fr3.ReturnValue5,
                                fr3.ReturnValue6, fr3.ReturnValue7, fr3.ReturnValue8);
                        }
                        this.Refresh();
                    }
                    //MessageBox.Show(s.Checkneighbors(selectedPosition).ToString());
                    break;
            }
        }

        private void stopBtn_Click(object sender, EventArgs e)
        {
            if (backgroundWorkerSimulation.WorkerSupportsCancellation == true)
            {
                // Cancel the asynchronous operation.
                backgroundWorkerSimulation.CancelAsync();
                playBtn.Enabled = true;
                pauseBtn.Enabled = false;
                run = false;
                s.StopSimulation();
                this.Refresh();
            }
        }

        private void newBtn_Click(object sender, EventArgs e)
        {
            DialogResult dialogResult = MessageBox.Show("This will delete and create new project \n Are you sure?", "New project", MessageBoxButtons.YesNo);
            if (dialogResult == DialogResult.Yes)
            {
                playBtn.Enabled = true;
                pauseBtn.Enabled = false;
                s = new Simulation(
                    new Size(4, 3),
                    new Point(20, 20),
                    new Size(200, 200));
                run = false;
                s.StopSimulation();
                this.Refresh();
            }
            else if (dialogResult == DialogResult.No)
            {
                //do something else
            }
        }

        private void saveBtn_Click(object sender, EventArgs e)
        {

            playBtn.Enabled = true;
            pauseBtn.Enabled = false;
            run = false;
            saveFileDialog1.InitialDirectory = Application.StartupPath;
            saveFileDialog1.DefaultExt = "sim";
            saveFileDialog1.Filter = "Simulation files (*.sim)|*.sim|All files (*.*)|*.*";
            DialogResult result1 = saveFileDialog1.ShowDialog();
            if (result1 == DialogResult.OK)
            {
                this.SaveSimulation(saveFileDialog1.FileName);
                // isSaved = true;
                currentfile = saveFileDialog1.FileName;
                //circuit.AreChangesSaved = true;
            }
        }
        private void SaveSimulation(string fileName)
        {
            try
            {
                binaryHelper.serializeObject(fileName, s);
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
            }
        }

        private void openBtn_Click(object sender, EventArgs e)
        {
            if (s.isSaveRequired == true)
            {
                if ((MessageBox.Show("Do you want to save the current simulation before loading another one?", "simulation", MessageBoxButtons.YesNo)) == DialogResult.Yes)
                {
                    s.isSaveRequired = false;
                    this.saveBtn_Click(sender, e);
                }

            }
            else
            {
                DialogResult d = openFileDialog1.ShowDialog();
                openFileDialog1.DefaultExt = "sim";
                openFileDialog1.Filter = "Simulation files (*.sim)|*.sim|All files (*.*)|*.*";
                if (d == DialogResult.OK)
                {
                    this.LoadFile(openFileDialog1.FileName);
                }

            }

        }
        private void LoadFile(string filename)
        {
            SFromFile = binaryHelper.deSerializeObject(filename);

            this.DoubleBuffered = true;
            s = new Simulation(
               new Size(4, 3),
               new Point(20, 20),
               new Size(200, 200));

            s.cMap = SFromFile.cMap;
            for (int i = 0; i < SFromFile.cMap.Length; i++)
            {
                if (SFromFile.cMap[i] != null)
                {
                    s.AddCrossing(i, SFromFile.cMap[i].CType);

                }
            }
            this.Refresh();

        }
        public object GetSimulation()
        {
            var temp = s;
            return temp;
        }

        private void btnSetTrafficOutEddges_Click(object sender, EventArgs e)
        {


            // Ntemp.TabIndex = 2;
            int x;
            int counter = 0;
            foreach (Sim.Cross c in s.cMap)
            {
                if (c != null)
                {
                    x = s.Checkneighbors(counter);
                    if (x % 10 == 1)
                    {
                        x /= 10;
                        x *= 10;
                        CheckEdges[0] = 1;

                    }
                    if (x % 100 == 10)
                    {

                        x /= 100;
                        x *= 100;
                        CheckEdges[1] = 1;


                    }
                    if (x % 1000 == 100)
                    {

                        x /= 1000;
                        x *= 1000;
                        CheckEdges[2] = 1;

                    }
                    if (x % 10000 == 1000)
                    {

                        x /= 10000;
                        x *= 10000;
                        CheckEdges[3] = 1;

                    }
                    for (int i = 0; i < CheckEdges.Length; i++)
                    {

                        if (CheckEdges[0] < 1)
                        {
                            NumericUpDown Ntemp = new NumericUpDown();
                            Ntemp.Location = new System.Drawing.Point(c.pointCentralLines[0].X, c.pointCentralLines[0].Y);
                            Ntemp.Name = "toptrafficout";
                            Ntemp.Size = new System.Drawing.Size(40, 20);
                            this.grid.Controls.Add(Ntemp);
                            //TrafficOutValues.Add();
                            Ntemp.Value = (int)c.roads[0].trafficOut;
                            Ntemp.Tag = new TrafficOutSettings(counter, 0);
                            Ntemp.ValueChanged += new System.EventHandler(this.Ntemp_ValueChanged);
                        }
                        if (CheckEdges[1] < 1)
                        {
                            NumericUpDown Ntemp = new NumericUpDown();
                            Ntemp.Location = new System.Drawing.Point(c.pointCentralLines[2].X, c.pointCentralLines[2].Y);
                            Ntemp.Name = "righttrafficout";
                            Ntemp.Size = new System.Drawing.Size(40, 20);
                            this.grid.Controls.Add(Ntemp);
                            Ntemp.Value = (int)c.roads[1].trafficOut;
                            Ntemp.Tag = new TrafficOutSettings(counter, 1);
                            Ntemp.ValueChanged += new System.EventHandler(this.Ntemp_ValueChanged);
                        }
                        if (CheckEdges[2] < 1)
                        {
                            NumericUpDown Ntemp = new NumericUpDown();
                            Ntemp.Location = new System.Drawing.Point(c.pointCentralLines[4].X, c.pointCentralLines[4].Y);
                            Ntemp.Name = "Bottomttrafficout";
                            Ntemp.Size = new System.Drawing.Size(40, 20);

                            this.grid.Controls.Add(Ntemp);
                            Ntemp.Value = (int)c.roads[2].trafficOut;
                            Ntemp.Tag = new TrafficOutSettings(counter, 2);
                            Ntemp.ValueChanged += new System.EventHandler(this.Ntemp_ValueChanged);
                        }
                        if (CheckEdges[3] < 1)
                        {
                            NumericUpDown Ntemp = new NumericUpDown();
                            Ntemp.Location = new System.Drawing.Point(c.pointCentralLines[6].X, c.pointCentralLines[6].Y);
                            Ntemp.Name = "Lefttrafficout";
                            Ntemp.Size = new System.Drawing.Size(40, 20);
                            this.grid.Controls.Add(Ntemp);
                            Ntemp.Value = (int)c.roads[3].trafficOut;
                            Ntemp.Tag = new TrafficOutSettings(counter, 3);
                            Ntemp.ValueChanged += new System.EventHandler(this.Ntemp_ValueChanged);
                        }
                    }
                }// end null check array
                counter++;
                Array.Clear(CheckEdges, 0, CheckEdges.Length);
            }//end foreach


        }
        private void Ntemp_ValueChanged(object sender, EventArgs e)
        {
            NumericUpDown N = (NumericUpDown)sender;
            TrafficOutSettings T = (TrafficOutSettings)N.Tag;
            s.cMap[T.Location].roads[T.Road].trafficOut = (int)N.Value;

        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            foreach (NumericUpDown Nu in grid.Controls)
            {
                Nu.Visible = false;
            }
        }

        private void statisticsBtn_Click(object sender, EventArgs e)
        {
            int linesBreak = 0;
            int counter = 0;
            string CrossingId;
            foreach (Sim.Cross c in s.cMap)
            {
                if (c != null)
                {
                    foreach (Sim.Road R in c.roads)
                    {
                        foreach (Sim.LaneIn L in R.lanesIn)
                        {
                            Label label = new Label();
                            Label totalCars = new Label();
                            Label totalCarsPerCrossing = new Label();
                            label.Location = new System.Drawing.Point(0, linesBreak + 17);
                            label.AutoSize = true;
                            CrossingId = GetCrossingId(counter);
                            label.Text = "Crossing : " + CrossingId + ", Lane ID: " + " Lane IN " + ", Cars : " + L.carsOnLane.Count.ToString();
                            // totalCars.Text = L.countCars().ToString();
                            // totalCarsPerCrossing.Text = L.countCars().ToString();
                            panel2.Controls.Add(label);
                            // CarsPerCrossings += Convert.ToInt32(totalCarsPerCrossing.Text);

                            linesBreak = label.Location.Y;
                        }
                        foreach (Sim.LaneOut L in R.lanesOut)
                        {
                            Label label = new Label();
                            Label totalCars = new Label();
                            Label totalCarsPerCrossing = new Label();
                            label.Location = new System.Drawing.Point(0, linesBreak + 17);
                            label.AutoSize = true;
                            CrossingId = GetCrossingId(counter);
                            label.Text = "Crossing : " + CrossingId + ", Lane ID: " + " Lane Out " + ", Cars : " + L.carsOnLane.Count.ToString();
                            // totalCars.Text = L.countCars().ToString();
                            // totalCarsPerCrossing.Text = L.countCars().ToString();
                            panel2.Controls.Add(label);
                            // CarsPerCrossings += Convert.ToInt32(totalCarsPerCrossing.Text);

                            linesBreak = label.Location.Y;
                        }
                    }
                }
                counter++;
            }
            
        }
        public string GetCrossingId(int Location)
        {
            switch (Location)
            { 
                case 0:
                    return "1A";
                    
                case 1:
                    return "1B";
                   
                case 2:
                    return "1C";
                   
                case 3:
                    return "1D";
                   
                case 4:
                    return "2A";
                   
                case 5:
                    return "2B";
                   
                case 6:
                    return "2C";
                  
                case 7:
                    return "2D";
                 
                case 8:
                    return "3A";
                    
                case 9:
                    return "3B";
                    
                case 10:
                    return "3C";
                   
                case 11:
                    return "3D";
                default:
                    return "";
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (s.isSaveRequired == true)
            {
                if ((MessageBox.Show("Do you want to save the current simulation before exiting?", "simulation", MessageBoxButtons.YesNo)) == DialogResult.Yes)
                {
                    s.isSaveRequired = true;
                    this.saveBtn_Click(sender, e);
                }
            }
        }

    }
    public class TrafficOutSettings
    {
        public int Location;

        public int Road;
        // public NumericUpDown valueHolder;
        public TrafficOutSettings(int loc, int R)
        {

            Location = loc;

            Road = R;
        }
    }
}
